//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<frame_composition.fx>
///	@path	~/xeres.engine/res/fx/
///	@date	2008/09/25
///	@desc	For FrameComposition class use, to composite frame to desktop.

#ifdef _D3D10

// DirectX 10 version.

#include "blending_10.fxh"

struct VS_OUTPUT
{
	float4	Position: SV_POSITION;
	float2	uv : TEXCOORD;
};

DepthStencilState DisableDepth
{
    DepthEnable = False;
    DepthWriteMask = ALL;
    DepthFunc = LESS_EQUAL;
};

// Pass through vertex shader.
VS_OUTPUT PassThrough( float4 position: POSITIONT , float2 texcoord : TEXCOORD )
{
	VS_OUTPUT Out;
	Out.Position = position;
	Out.uv = texcoord;
	return Out;
}

// In this pass we directly draw frame to screen.
Texture2D FrameTexture;
SamplerState DirectSampler
{
    Filter = MIN_MAG_MIP_POINT;
    AddressU = Wrap;
    AddressV = Wrap;
};

float4 FrameDirectThrought( VS_OUTPUT In ) : SV_Target
{
	return FrameTexture.Sample( DirectSampler , In.uv );
}

technique10 RenderFrame {
	pass p0 {
		// states
		SetDepthStencilState( DisableDepth , 0 );
		SetBlendState( RegularBlending , float4(1,1,1,1) , 0xffffffff );
		// shader
		SetVertexShader( CompileShader( vs_4_0 , PassThrough() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0 , FrameDirectThrought() ) );
	}
}

// This shader use to downsample the frame in order to make them blurred.
Texture2D BlurTexture;
SamplerState BlurSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

float2 DownSampleOffsets[9];

float4 DownSample( VS_OUTPUT In ) : SV_Target {
	float4 average = { 0.0f, 0.0f, 0.0f, 0.0f };
	for( int i = 0; i < 9; i++ )
		average += BlurTexture.Sample( BlurSampler, In.uv + DownSampleOffsets[i] );
	average /= 9.f;
	return average;
}
technique10 RenderDownsample {
    pass p0 {
		// states
		SetDepthStencilState( DisableDepth , 0 );
		SetBlendState( NoBlending , float4(1,1,1,1) , 0xffffffff );
		// shader
		SetVertexShader( CompileShader( vs_4_0 , PassThrough() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0 , DownSample() ) );
    }
}

float2 InvScreenSize;
float4 BlurParam;

float4 AeroEffectComposite( VS_OUTPUT In ) : SV_Target {
	float4 frame = FrameTexture.Sample( DirectSampler , In.uv );
	float2 uv = BlurParam.xy + In.uv * BlurParam.zw;
	float4 color = { 0.0f, 0.0f, 0.0f, 0.0f };
	color += BlurTexture.Sample( BlurSampler , uv );
	color += BlurTexture.Sample( BlurSampler , uv + float2( InvScreenSize.x , 0 ) );
	color += BlurTexture.Sample( BlurSampler , uv - float2( InvScreenSize.x , 0 ) );
	color += BlurTexture.Sample( BlurSampler , uv + float2( 0 , InvScreenSize.y ) );
	color += BlurTexture.Sample( BlurSampler , uv - float2( 0 , InvScreenSize.y ) );
	return color / 5;
}

technique10 RenderAero {
	// First we paste blury frame under.
    pass p0 {
		// states
		SetDepthStencilState( DisableDepth , 0 );
		SetBlendState( NoBlending , float4(1,1,1,1) , 0xffffffff );
		// shader
		SetVertexShader( CompileShader( vs_4_0 , PassThrough() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0 , AeroEffectComposite() ) );
    }
	// Then we cover frame over.
	pass p1 {
		// states
		SetBlendState( RegularBlending , float4(1,1,1,1) , 0xffffffff );
		// shader
		SetVertexShader( CompileShader( vs_4_0 , PassThrough() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0 , FrameDirectThrought() ) );
	}
}

#else

// DirectX 9 version.

// In this pass we directly draw frame to screen.
texture FrameTexture;
sampler FrameSampler = sampler_state
{
    Texture = <FrameTexture>;
    MinFilter = POINT;
    MagFilter = POINT;
	AddressU = WRAP;
	AddressV = WRAP;
};

float4 FrameDirectThrought( float2 t : TEXCOORD ) : COLOR
{
	return tex2D( FrameSampler , t );
}

technique RenderFrame {
	pass p0 {
		// depth states
		ZEnable = FALSE;
		// alpha states
		AlphaBlendEnable = True;
		SeparateAlphaBlendEnable = True;
		SrcBlend = SRCALPHA;
		DestBlend = INVSRCALPHA;
		BlendOp = ADD;
		SrcBlendAlpha = ONE;
		DestBlendAlpha = INVSRCALPHA;
		BlendOpAlpha = ADD;
		// shader
		VertexShader = NULL;
		PixelShader = compile ps_2_0 FrameDirectThrought();
	}
}

// This shader use to downsample the frame in order to make them blurred.
texture BlurTexture;
sampler BlurSampler = sampler_state
{
    Texture = <BlurTexture>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
	AddressU = WRAP;
	AddressV = WRAP;
};

float2 DownSampleOffsets[9];

float4 DownSample( float2 t : TEXCOORD ) : COLOR {
	float4 average = { 0.0f, 0.0f, 0.0f, 0.0f };
	for( int i = 0; i < 9; i++ )
		average += tex2D( BlurSampler, t + DownSampleOffsets[i] );
	average /= 9.f;
	return average;
}
technique RenderDownsample {
    pass p0 {
		// alpha state
		AlphaBlendEnable = False;
		SeparateAlphaBlendEnable = False;
		// shader
        VertexShader = NULL;
        PixelShader  = compile ps_2_0 DownSample();
    }
}

// Finally we use this shader to composite aero effects.
float2 InvScreenSize;
float4 BlurParam;

float4 AeroEffectComposite( float2 t : TEXCOORD ) : COLOR {
	float4 frame = tex2D( FrameSampler , t );
	float2 uv = BlurParam.xy + t * BlurParam.zw;
	float4 color = { 0.0f, 0.0f, 0.0f, 0.0f };
	color += tex2D( BlurSampler , uv );
	color += tex2D( BlurSampler , uv + float2( InvScreenSize.x , 0 ) );
	color += tex2D( BlurSampler , uv - float2( InvScreenSize.x , 0 ) );
	color += tex2D( BlurSampler , uv + float2( 0 , InvScreenSize.y ) );
	color += tex2D( BlurSampler , uv - float2( 0 , InvScreenSize.y ) );
	return color / 5;
}

technique RenderAero {
	// First we paste blury frame under.
    pass p0 {
		// depth states
		ZEnable = FALSE;
		// alpha states
		SeparateAlphaBlendEnable = False;
		AlphaBlendEnable = False;
		// shader
        VertexShader = NULL;
        PixelShader  = compile ps_2_0 AeroEffectComposite();
    }
	// Then we cover frame over.
	pass p1 {
		// depth states
		ZEnable = FALSE;
		// alpha states
		AlphaBlendEnable = True;
		SeparateAlphaBlendEnable = True;
		SrcBlend = SRCALPHA;
		DestBlend = INVSRCALPHA;
		BlendOp = ADD;
		SrcBlendAlpha = ONE;
		DestBlendAlpha = INVSRCALPHA;
		BlendOpAlpha = ADD;
		// shader
		VertexShader = NULL;
        PixelShader  = compile ps_2_0 FrameDirectThrought();
	}
}

#endif
